package com.loveyukari.service;

import com.loveyukari.common.exception.InternalException;
import com.loveyukari.dao.TourDao;
import com.loveyukari.model.Auth;
import com.loveyukari.model.TourUser;
import com.loveyukari.utils.AESUtils;
import com.loveyukari.utils.AliYunUtils;
import com.loveyukari.utils.HttpUtils;
import com.loveyukari.utils.RandomCodeUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class TourService {

    private Logger logger = LoggerFactory.getLogger(TourService.class);
    @Autowired
    private AuthService authService;
    @Autowired
    private TourDao tourDao;



    @Scheduled(cron = "55 1/10 * * * *")
    public void autoUpdateExclude(){

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = DateUtils.addMinutes(new Date(), -30);
        String format = sdf.format(date);
        logger.info("auto update exclude "+format);
        List<TourUser> list = tourDao.selectByCreateTime(format);
        for (TourUser tourUser :
                list) {
            if (tourUser.getExclude() != 0) {
                continue;
            }
            Auth auth = authService.getCacheAuth(tourUser.getAuthId());
            if (auth == null){
                continue;
            }
            List<JSONObject> tags = authService.getAuthBadge(tourUser.getAuthId());
            for (JSONObject json :
                    tags) {
                String name = json.optString("name");
                if ("196".equals(name)){
                    int lv = json.optInt("lv");
                    if (auth.getFansLv() != lv){
                        authService.updateAuthFansLv(lv,tourUser.getAuthId());
                    }
                }
                if ("总监".equals(name)){
                    tourDao.updateTourExclude(tourUser.getId(),1);
                }
            }
            List<JSONObject> yubaList = authService.getAuthYubaFollow(auth.getId());
            for (JSONObject json:
                 yubaList) {
                int groupId = json.optInt("groupId");
                if (groupId == 588){
                    tourDao.updateTourExclude(tourUser.getId(),1);
                }
            }
        }
    }


    public void updateExclude(int id,int exclude){
        tourDao.updateTourExclude(id, exclude);
    }


    public List<String> batchCreateTicketCode(int size,String city){
        ArrayList<String> result = new ArrayList<>();
        while(result.size() < size){
            try {
                String ticketCode = RandomCodeUtil.randomUpperCode(16);
                tourDao.insertTicketCode(ticketCode,city);
                result.add(ticketCode);
            } catch (Exception e) {
            }
        }
        return result;
    }

    public JSONObject checkCode(String code,String city) throws InternalException{
        logger.info("code is {}",code);
        if (StringUtils.isBlank(code)){
            throw new InternalException("解析失败: 请输入门票码");
        }
        code = code.toUpperCase();
        JSONObject json = tourDao.selectTourItemByTicketNo(code);
        if (json == null){
            throw new InternalException("解析失败: 门票码不存在");
        }
        if (!StringUtils.equals(json.optString("city"),city)){
            throw  new InternalException("解析失败: 场次信息错误");
        }
        int status = json.optInt("status");
        if (status == 1){
            int tourId = json.optInt("tourId");
            TourUser tourUser = tourDao.selectTourById(tourId);
            JSONObject result = new JSONObject();
            String phone = tourUser.getPhone();
            phone = phone.substring(0,3)+"****"+phone.substring(7,11);
            result.put("phone",phone);
            result.put("name",tourUser.getDouyuName());
            tourDao.updateTourItemStatus(tourId,city,2);
            return result;
        } else if (status == 0){
            throw new InternalException("解析失败: 未获得门票");
        } else if (status == 2){
            throw new InternalException("解析失败: 门票已使用");
        } else {
            throw new InternalException("解析失败: 门票状态异常");
        }
    }


    public JSONObject checkQr(String ticket,String city) throws InternalException{
        logger.info("ticket is {}",ticket);
        String s = this.decryptTicket(ticket);
        if (StringUtils.isBlank(s)){
            throw new InternalException("解析失败: 二维码无法解析");
        }
        String[] split = s.split(",");
        String type = split[0];

        if (StringUtils.equals(type,"1")){
            if (split.length != 4){
                throw new InternalException("解析失败: 二维码解析异常");
            }
            if (!StringUtils.equals(split[1],city)){
                throw  new InternalException("解析失败: 场次信息错误");
            }
            int authId = Integer.parseInt(split[3]);
            Integer tourId = tourDao.selectTourIdByAuthId(authId);
            if (tourId == null){
                throw  new InternalException("解析失败: 用户信息不存在");
            }
            Integer status = tourDao.selectTourItemStatus(tourId, city);
            if (status == null || status == -1){
                throw new InternalException("解析失败: 用户未报名");
            } else if (status == 0){
                throw new InternalException("解析失败: 用户未获得门票");
            } else if (status == 2){
                throw new InternalException("解析失败: 门票已使用");
            } else if (status == 1){
                JSONObject result = new JSONObject();
                Auth auth = authService.getCacheAuth(authId);
                result.put("name",auth.getName());
                String phone = split[2];
                phone = phone.substring(0,3)+"****"+phone.substring(7,11);
                result.put("phone",phone);
                tourDao.updateTourItemStatus(tourId,city,2);
                return result;
            } else {
                throw new InternalException("解析失败: 门票状态异常");
            }
        } else if (StringUtils.equals(type,"2")){
            if (split.length != 3){
                throw new InternalException("解析失败: 二维码解密失败");
            }
            if (!StringUtils.equals(split[1],city)){
                throw  new InternalException("解析失败: 场次信息错误");
            }
            String ticketCode = split[2];
            return this.checkTicketCode(ticketCode,city);
        } else {
            throw new InternalException("解析失败: 二维码类型不存在");
        }
    }

    public JSONObject checkTicketCode(String ticketCode,String city) throws InternalException {
        logger.info("ticket code is {}",ticketCode);
        if (StringUtils.isBlank(ticketCode)){
            throw new InternalException("解析失败: 请输入门票码");
        }
        ticketCode = ticketCode.toUpperCase();
        JSONObject ticketJson = tourDao.selectTicketCode(ticketCode);
        if (ticketJson == null){
            throw new InternalException("解析失败: 兑换码不存在");
        }
        if (!StringUtils.equals(city,ticketJson.optString("city"))){
            throw new InternalException("解析失败: 场次信息错误");
        }
        if (ticketJson.optInt("status",-1) != 0) {
            throw new InternalException("解析失败: 兑换码已使用");
        }
        JSONObject result = new JSONObject();
        result.put("name","兑换码用户");
        tourDao.updateTicketCode(ticketCode);
        return result;
    }


   public void updateTicket(int tourId,String city,int status){
       if (tourDao.selectTourItemStatus(tourId, city) == null){
           tourDao.insertTourItem(tourId,city);
       }
       tourDao.updateTourItemStatus(tourId,city,status);
       if (status == 1){
           String ticketNo = createTicketNo(city);
           tourDao.updateTicketNo(tourId,city,ticketNo);
           new SendMessage(tourId,city).start();
       }
   }

    public List<JSONObject> list(String city){
        List<JSONObject> list = tourDao.selectByCity(city);
        return list;
    }


    public List<Auth> getCityAuth(String type,Integer status){
        Map<Integer, Integer> map = tourDao.selectDraw(type,status);
        Set<Integer> set = map.keySet();
        ArrayList<Auth> result = new ArrayList<>();
        for (Integer authId:
             set) {
            Auth auth = authService.getCacheAuth(authId);
            if (auth != null){
                result.add(auth);
            }
        }
        return result;
    }


    public List<Auth> draw(int size,String city,Integer status) throws InternalException{
        Map<Integer, Integer> map = tourDao.selectDraw(city,status);
        Set<Integer> set = map.keySet();
        if (set.size() < size){
            throw new InternalException("抽奖人数过少");
        }
        ArrayList<Auth> list = new ArrayList<>();
        int total = 0;
        for (Integer authId:
                set) {
            Auth auth = authService.getCacheAuth(authId);
            if (auth != null){
                list.add(auth);
                if (StringUtils.equals(city,"shanghai") && status == 1){
                    total += this.getWeightJijiu(auth.getFansLv());
                } else {
                    total += this.getWeight(auth.getFansLv());
                }
            }
        }
        Random random = new Random();
        ArrayList<Auth> result = new ArrayList<>();
        HashSet<Integer> authIds = new HashSet<>();
        while (result.size() < size) {
            int t = random.nextInt(total);
            for (Auth auth :
                    list) {
                int weight = 0;
                if (StringUtils.equals(city,"shanghai") && status == 1){
                    weight = this.getWeightJijiu(auth.getFansLv());
                } else {
                    weight = this.getWeight(auth.getFansLv());
                }

                if (t < weight){
                    //本轮抽奖查重
                    Integer authId = auth.getId();
                    if (authIds.add(authId)){
                        Integer tourId = map.get(authId);
                        if (this.giveTicet(tourId,city) || (StringUtils.equals(city,"shanghai") && status == 1)){
                            result.add(auth);
                            if (StringUtils.equals(city,"shanghai") && status == 1){
                            } else {
//                                new SendMessage(tourId,city).start();
                            }
                        }
                    }
                    break;
                }
                t = t - weight;
            }
        }
        return result;
    }

    private String createTicketNo(String city){
        SimpleDateFormat sdf = new SimpleDateFormat("HHmmssSSS");
        String code = RandomCodeUtil.randomNumberCode(3);
        switch (city){
            case "chengdu":return "CD"+sdf.format(new Date())+code;
            case "beijing":return "BJ"+sdf.format(new Date())+code;
            case "guangzhou":return "GZ"+sdf.format(new Date())+code;
            case "shanghai":return "SH"+sdf.format(new Date())+code;
        }
        return "T"+sdf.format(new Date())+code;
    }

    private Map<String,String> cityTemplateMap = new HashMap<>();
    {
        cityTemplateMap.put("chengdu","SMS_138078411");
        cityTemplateMap.put("beijing","SMS_138073623");
        cityTemplateMap.put("guangzhou","SMS_138063791");
        cityTemplateMap.put("shanghai","SMS_138078618");
    }


    private class SendMessage extends Thread {

        private int tourId;
        private String city;

        public SendMessage(int tourId,String city) {
            this.tourId = tourId;
            this.city = city;
        }

        @Override
        public void run() {
            String msgNo = cityTemplateMap.get(city);
            if (StringUtils.isEmpty(msgNo)){
                return;
            }
            TourUser tourUser = tourDao.selectTourById(tourId);
            if (StringUtils.isNotBlank(tourUser.getPhone())){
                AliYunUtils.send(msgNo,tourUser.getPhone(),null);
            }
        }
    }

    private boolean giveTicet(int tourId,String city){
        Integer status = tourDao.selectTourItemStatus(tourId, city);
        if (status == null){
            return false;
        }
        if (status == 0){
            //发票，发短信
            tourDao.updateTourItemStatus(tourId,city,1);
            String ticketNo = createTicketNo(city);
            tourDao.updateTicketNo(tourId,city,ticketNo);
            return true;
        }
        return false;
    }

    private int getWeight(int lv){
        if (lv < 15){
            return 0;
        }
        return 1;
    }

    private int getWeightJijiu(int lv){
        if (lv < 18){
            return 0;
        }
        if (lv < 22){
            return (int)Math.floor(Math.pow(lv-10,2)/2);
        }
        return (int)Math.floor(Math.pow(lv-10,2));
    }






    public JSONObject cancel(String token,String city) throws InternalException {
        TourUser tourUser = tourDao.selectTourByToken(token);
        if (tourUser == null) {
            throw new InternalException("您未报名登记");
        }
        Integer status = tourDao.selectTourItemStatus(tourUser.getId(), city);
        if (status == null || status == -1){
            throw new InternalException("您未报名登记");
        }
        if (status > 1){
            throw new InternalException("您已获得门票，无法取消报名");
        }
        tourDao.updateTourItemStatus(tourUser.getId(),city,-1);
        return this.getTourUserByToken(token,city);
    }

    public JSONObject addTourUser(String douyuName,String qq,String phone,String city,String ip) throws InternalException {
        TourUser tourUser = tourDao.selectTourByPhone(phone);
        //判断手机是否登记
        if (tourUser == null){
            //判断斗鱼ID是否重复
            Auth auth = authService.findAuthByName(douyuName);
            if (auth == null){
                throw new InternalException("斗鱼ID不存在，请检查。新注册用户请在196发送弹幕后登记。");
            }
            Integer tourId = tourDao.selectTourIdByAuthId(auth.getId());
            if (tourId != null){
                throw new InternalException("斗鱼ID已被登记，请使用其他ID或联系管理员");
            }
            //判断斗鱼ID是否存在

            //生成token
            String token = "";
            token = RandomCodeUtil.randomUpperCode(32);
            //插入用户
            tourDao.insertTour(douyuName, auth.getId(), phone, qq,token,ip);
            tourUser = tourDao.selectTourByPhone(phone);
        }
        //判断是否已经登记
        Integer status = tourDao.selectTourItemStatus(tourUser.getId(), city);
        if (status == null){
            //从未报名该场次
            tourDao.insertTourItem(tourUser.getId(),city);
            return createResult(tourUser,city,0);
        }
        if (status == -1){
            //取消重新报名
            tourDao.updateTourItemStatus(tourUser.getId(),city,0);
            return createResult(tourUser,city,0);
        }
        return createResult(tourUser,city,status);
    }

    public JSONObject getTourUserByToken(String token,String city) {
        TourUser tourUser = tourDao.selectTourByToken(token);
        if (tourUser == null){
            return new JSONObject();
        }
        Integer status = tourDao.selectTourItemStatus(tourUser.getId(), city);
        tourDao.updateLastLoginTime(tourUser.getId(),city);
        return createResult(tourUser,city,status);
    }

    public JSONObject getTourUserByPhone(String phone,String city) {
        TourUser tourUser = tourDao.selectTourByPhone(phone);
        if (tourUser == null){
            return new JSONObject();
        }
        Integer status = tourDao.selectTourItemStatus(tourUser.getId(), city);
        tourDao.updateLastLoginTime(tourUser.getId(),city);
        return createResult(tourUser,city,status);
    }


    private JSONObject createResult(TourUser tourUser,String city, Integer status)  {
        JSONObject json = JSONObject.fromObject(tourUser);
        if (status == null){
            status = -1;
        }
        json.put("status",status);
        json.put("city",city);
        json.remove("id");
        json.remove("ip");
        if (status == 1){
            json.put("ticket",createTicket(tourUser.getPhone(),tourUser.getAuthId(),city));
            json.put("ticketNo",tourDao.selectTicketNo(tourUser.getId(),city));
        }
        return json;
    }

    public static void main(String[] args) {
        TourService tourService = new TourService();
        String beijing = tourService.createTicket("18868877652", 51126709, "beijing");
        System.out.println(beijing);
    }


    private String YUKARI_TOUR_TICKET_KEY = "C3B694DD570AEC8D040796B0E298700D";
    private String createTicket(String phone,Integer authId,String city) {
        StringBuilder sb = new StringBuilder();
        sb.append("1,").append(city).append(",").append(phone).append(",").append(authId);
        String ticket = "";
        try {
            ticket = AESUtils.encrypt(sb.toString(), YUKARI_TOUR_TICKET_KEY);
        } catch (Exception e) {
            logger.error(sb.toString(),e);
        }
        return ticket;
    }


    public String decryptTicket(String ticket){
        try {
            String result = AESUtils.decrypt(ticket, YUKARI_TOUR_TICKET_KEY);
            return result;
        } catch (Exception e) {
            logger.error(ticket,e);
        }
        return null;
    }



}
